import type { DiscussionAnalytics } from '../../index'
import type {
  DiscussionUserRolesDistribution,
  DiscussionUserStats,
} from '../../types'
import type { DiscussionScoreAnalysisReport } from './types'
import { logger } from '../../../../../../types/constants'
import { DiscussionUserRole } from '../../types'
import {
  DISCUSSION_HEAT_SCORE_CONFIG,
  DISCUSSION_MAX_SCORE_LIMITS,
  DISCUSSION_SCORE_WEIGHT_CONFIG,
} from './types'

export class DiscussionAnalyticsScore {
  readonly name: string = 'DiscussionAnalyticsScore'
  private static instance: DiscussionAnalyticsScore

  constructor(private discussionInstance: DiscussionAnalytics) {}

  /**
   * 获取单例实例
   */
  public static getInstance(discussionInstance: DiscussionAnalytics): DiscussionAnalyticsScore {
    if (!DiscussionAnalyticsScore.instance) {
      DiscussionAnalyticsScore.instance = new DiscussionAnalyticsScore(discussionInstance)
    }
    return DiscussionAnalyticsScore.instance
  }

  /**
   * 计算讨论热度分数
   * 基于评论数量、参与人数、最近活跃度、关键人物参等多个维度加权计算
   * @returns {number} 热度分数
   */
  calculateHeatScore(): number {
    const defaultScore = DISCUSSION_SCORE_WEIGHT_CONFIG.minScore

    if (!this.discussionInstance.analyticsData) {
      logger.warn(`[${this.name}] 无分析数据，返回默认热度分数`)
      return defaultScore
    }

    const {
      totalComments,
      uniqueParticipants,
      userRoles,
      timeMetrics,
      mostActiveUser,
    } = this.discussionInstance.analyticsData

    logger.debug(`[${this.name}] 开始计算热度分数`, {
      totalComments,
      uniqueParticipants,
      hoursSinceUpdate: timeMetrics.hoursSinceLastUpdate,
    })

    try {
      let score = defaultScore

      // 1. 计算评论数量得分
      const commentScore = this.calculateCommentScore(totalComments)
      score += commentScore

      // 2. 计算参与人数得分
      const participantScore = this.calculateParticipantScore(uniqueParticipants)
      score += participantScore

      // 3. 计算最近活跃度得分
      const recencyScore = this.calculateRecencyScore(timeMetrics.hoursSinceLastUpdate)
      score += recencyScore

      // 4. 计算关键人物参与得分
      const keyPersonScore = this.calculateKeyPersonScore(userRoles, mostActiveUser)
      score += keyPersonScore

      // 确保分数在有效范围内
      const finalScore = this.normalizeScore(score)

      logger.info(`[${this.name}] 热度计算完成`, {
        finalScore,
        commentScore,
        participantScore,
        recencyScore,
        keyPersonScore,
        baseScore: defaultScore,
      })

      return finalScore
    }
    catch (error: any) {
      logger.error(`[${this.name}] 热度计算失败`, error)
      return DISCUSSION_SCORE_WEIGHT_CONFIG.maxScore / 2
    }
  }

  /**
   * 计算评论数量得分
   * @param {number} totalComments - 总评论数
   * @returns {number} 评论数量得分
   */
  private calculateCommentScore(totalComments: number): number {
    const rawScore = totalComments * DISCUSSION_SCORE_WEIGHT_CONFIG.commentWeight
    const finalScore = Math.min(rawScore, DISCUSSION_MAX_SCORE_LIMITS.comments)

    logger.debug(`[${this.name}] 评论数量得分计算`, {
      totalComments,
      weight: DISCUSSION_SCORE_WEIGHT_CONFIG.commentWeight,
      rawScore,
      finalScore,
    })

    return finalScore
  }

  /**
   * 计算参与人数得分
   * @param {number} uniqueParticipants - 唯一参与者数量
   * @returns {number} 参与人数得分
   */
  private calculateParticipantScore(uniqueParticipants: number): number {
    const rawScore = uniqueParticipants * DISCUSSION_SCORE_WEIGHT_CONFIG.participantWeight
    const finalScore = Math.min(rawScore, DISCUSSION_MAX_SCORE_LIMITS.participants)

    logger.debug(`[${this.name}] 参与人数得分计算`, {
      uniqueParticipants,
      weight: DISCUSSION_SCORE_WEIGHT_CONFIG.participantWeight,
      rawScore,
      finalScore,
    })

    return finalScore
  }

  /**
   * 计算最近活跃度得分
   * @param {number} hoursSinceLastUpdate - 距离上次更新的小时数
   * @returns {number} 最近活跃度得分
   */
  private calculateRecencyScore(hoursSinceLastUpdate: number): number {
    const recencyConfig = DISCUSSION_SCORE_WEIGHT_CONFIG.recencyWeights.find(
      config => hoursSinceLastUpdate <= config.maxHours,
    )

    const score = recencyConfig?.score ?? 0

    logger.debug(`[${this.name}] 最近活跃度得分计算`, {
      hoursSinceLastUpdate,
      matchedConfig: recencyConfig,
      score,
    })

    return Math.min(score, DISCUSSION_MAX_SCORE_LIMITS.recency)
  }

  /**
   * 计算关键人物参与得分
   * 楼主、作者、管理员的参与会显著提高热度
   * @param {DiscussionUserRolesDistribution} userRoles - 用户角色分布
   * @param {DiscussionUserStats | null} mostActiveUser - 最活跃用户
   * @returns {number} 关键人物参与得分
   */
  private calculateKeyPersonScore(
    userRoles: DiscussionUserRolesDistribution,
    mostActiveUser: DiscussionUserStats | null,
  ): number {
    let score = 0
    const weights = DISCUSSION_SCORE_WEIGHT_CONFIG.keyPersonWeights

    // 基础关键人物参与得分
    if (userRoles[DiscussionUserRole.OriginalPoster] > 0) {
      score += weights.originalPoster
    }
    if (userRoles[DiscussionUserRole.Author] > 0) {
      score += weights.author
    }
    if (userRoles[DiscussionUserRole.Admin] > 0) {
      score += weights.admin
    }

    // 最活跃用户额外加分
    if (mostActiveUser) {
      const bonusWeights = DISCUSSION_SCORE_WEIGHT_CONFIG.activeUserBonus
      const activeUserRole = mostActiveUser.role

      if (activeUserRole === DiscussionUserRole.OriginalPoster) {
        score += bonusWeights.originalPoster
      }
      else if (activeUserRole === DiscussionUserRole.Author) {
        score += bonusWeights.author
      }
      else if (activeUserRole === DiscussionUserRole.Admin) {
        score += bonusWeights.admin
      }
    }

    const finalScore = Math.min(score, DISCUSSION_MAX_SCORE_LIMITS.keyPersons)

    logger.debug(`[${this.name}] 关键人物参与得分计算`, {
      userRoles,
      mostActiveUser: mostActiveUser?.name,
      baseScore: score,
      finalScore,
    })

    return finalScore
  }

  /**
   * 标准化分数到有效范围
   * @param {number} score - 原始分数
   * @returns {number} 标准化后的分数
   */
  private normalizeScore(score: number): number {
    const normalized = Math.max(
      DISCUSSION_SCORE_WEIGHT_CONFIG.minScore,
      Math.min(DISCUSSION_SCORE_WEIGHT_CONFIG.maxScore, Math.round(score)),
    )
    logger.debug(`[${this.name}] 分数标准化`, {
      originalScore: score,
      normalizedScore: normalized,
      minScore: DISCUSSION_SCORE_WEIGHT_CONFIG.minScore,
      maxScore: DISCUSSION_SCORE_WEIGHT_CONFIG.maxScore,
    })

    return normalized
  }

  /**
   * 根据热度分数获取对应的颜色
   * @param {number} score - 热度分数
   * @returns {string} 对应的颜色代码
   */
  getHeatColor(score: number): string {
    // 按阈值降序查找匹配的配置
    const matchedConfig = DISCUSSION_HEAT_SCORE_CONFIG
      .sort((a, b) => b.threshold - a.threshold)
      .find(config => score >= config.threshold)

    return matchedConfig?.color || DISCUSSION_HEAT_SCORE_CONFIG[DISCUSSION_HEAT_SCORE_CONFIG.length - 1].color
  }

  /**
   * 根据热度分数获取对应的图标
   * @param {number} score - 热度分数
   * @returns {string} 对应的图标
   */
  getHeatIcon(score: number): string {
    const matchedConfig = DISCUSSION_HEAT_SCORE_CONFIG
      .sort((a, b) => b.threshold - a.threshold)
      .find(config => score >= config.threshold)

    return matchedConfig?.icon || DISCUSSION_HEAT_SCORE_CONFIG[DISCUSSION_HEAT_SCORE_CONFIG.length - 1].icon
  }

  /**
   * 根据热度分数获取对应的标签
   * @param {number} score - 热度分数
   * @returns {string} 对应的标签文本
   */
  getHeatLabel(score: number): string {
    const matchedConfig = DISCUSSION_HEAT_SCORE_CONFIG
      .sort((a, b) => b.threshold - a.threshold)
      .find(config => score >= config.threshold)

    return matchedConfig?.label || DISCUSSION_HEAT_SCORE_CONFIG[DISCUSSION_HEAT_SCORE_CONFIG.length - 1].label
  }

  /**
   * 获取完整的分数分析报告
   */
  getScoreAnalysisReport(): DiscussionScoreAnalysisReport | null {
    if (!this.discussionInstance.analyticsData) {
      return null
    }

    const {
      totalComments,
      uniqueParticipants,
      userRoles,
      timeMetrics,
      mostActiveUser,
    } = this.discussionInstance.analyticsData

    const heatScore = this.calculateHeatScore()

    return {
      finalScore: heatScore,
      scoreBreakdown: {
        baseScore: 50,
        commentScore: this.calculateCommentScore(totalComments),
        participantScore: this.calculateParticipantScore(uniqueParticipants),
        recencyScore: this.calculateRecencyScore(timeMetrics.hoursSinceLastUpdate),
        keyPersonScore: this.calculateKeyPersonScore(userRoles, mostActiveUser),
      },
      heatLevel: {
        color: this.getHeatColor(heatScore),
        icon: this.getHeatIcon(heatScore),
        label: this.getHeatLabel(heatScore),
      },
      config: {
        maxScore: DISCUSSION_SCORE_WEIGHT_CONFIG.maxScore,
        limits: DISCUSSION_MAX_SCORE_LIMITS,
      },
    }
  }
}
